package p06_Aware与InitializingBean;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.context.annotation.*;
import org.springframework.context.support.GenericApplicationContext;

import javax.annotation.PostConstruct;

/**
 * 扩展功能(后处理器提供的功能)会失效，而spring原生功能不会失效
 * 什么情况下扩展功能会失效呢
 */
@Configuration
public class _3_bean后处理器失效的情况 implements BeanNameAware, InitializingBean {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        //添加测试bean
        context.registerBean(_3_bean后处理器失效的情况.class);
        //添加后处理器
        context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
        context.registerBean(CommonAnnotationBeanPostProcessor.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        //运行后处理器，看会不会执行后处理器扩展的功能
        context.refresh();

        context.close();
        /**
         * 最后发现，spring原生功能接口没有失效，但是@Autowired、@Value、@PostConstruct失效了
         * 为什么呢?
         *    context.refresh()方法的执行顺序:
         *      1.执行BeanFactory后处理器(因为收集bean定义数据的功能，也是一个BeanFactory后处理器完成的);
         *      2.注册Bean后处理器(先注册放着，后面初始化单例bean时，在bean生命周期的各个阶段会回调bean后处理器的方法);
         *      3.创建和初始化单例(回调bean后处理器，进行生命周期的扩展，包括注入属性，执行初始化方法等)
         *      4.如果一个bean实现了Aware、InitializingBean等接口，会去回调相关方法
         *      5.一个bean创建成功
         *
         *    -也就是说，首先收集并执行所有BeanFactory后处理器，这是万里长征第一步，也是最重要的一步
         *    -当前配置类有个@Bean方法，这个@Bean方法返回一个BeanFactory后处理器，spring必须优先准备好所有BeanFactory后处理器
         *    -而想要得到当前类定义的BeanFactory后处理器，又必须先初始化当前配置类bean
         *    -所以spring调整了当前配置类初始化的顺序，步骤变成了:3 -> 4 -> 5(当前配置类bean创建成功后，就调用方法获得BeanFactory后处理器) -> 1 -> 2
         *    -所以初始化当前配置类bean时，容器中还没有bean后处理器呢，也就无法回调bean后处理器的方法扩展当前bean的生命周期，所以@Autowired、@Value、@PostConstruct失效了
         */
    }

    //spring原生功能
    @Override
    public void setBeanName(String name) {
        System.out.println("spring原生注入:" + name);
    }

    //spring原生功能
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("spring原生初始化");
    }

    @Autowired
    public void autowired(@Value("${JAVA_HOME}") String home) {
        System.out.println("后处理器扩展的注入:" + home);
    }

    @PostConstruct
    public void init() {
        System.out.println("后处理器扩展的初始化");
    }

    //下面的代码会让后处理器提供的扩展功能失效
    @Bean
    public BeanFactoryPostProcessor postProcessor() {
        return beanFactory -> {
            System.out.println("执行BeanFactoryPostProcessor");
        };
    }
}
